package com.fengye.revoker;

import com.fengye.model.RemoteResponse;
import com.fengye.model.RemoteResponseWrapper;
import com.google.common.collect.Maps;

import java.util.Map;
import java.util.concurrent.*;

/**
 * @Author fengye
 * @Date 2023/2/14 20:01
 **/
public class RevokerResponseHolder {

    /** 服务返回结果Map */
    private final static Map<String, RemoteResponseWrapper> responseMap = Maps.newConcurrentMap();

    private final static ScheduledExecutorService removeExpireKeyExecutor = new ScheduledThreadPoolExecutor(1);
    static {
        // 定时任务，删除超时未获取到结果的key，防止内存泄露
        removeExpireKeyExecutor.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                for (Map.Entry<String, RemoteResponseWrapper> entry : responseMap.entrySet()) {
                    boolean isExpire = entry.getValue().isExpire();
                    if(isExpire) {
                        responseMap.remove(entry.getKey());
                    }
                }
            }
        }, 10, 10, TimeUnit.MICROSECONDS);
    }

    /**
     * 初始化返回结果容器，requestUniqueKey唯一标识本次调用
     *
     * @param requestUniqueKey
     */
    public static void initResponseData(String requestUniqueKey) {
        responseMap.put(requestUniqueKey, RemoteResponseWrapper.of());
    }

    /**
     * 将Netty调用异步返回结果放入阻塞队列
     * @param response
     */
    public static void putResultValue(RemoteResponse response) {
        long currentTime = System.currentTimeMillis();
        RemoteResponseWrapper remoteResponseWrapper = responseMap.get(response.getUniqueKey());
        remoteResponseWrapper.setResponseTime(currentTime);
        remoteResponseWrapper.getResponseQueue().add(response);
        responseMap.put(response.getUniqueKey(), remoteResponseWrapper);
    }

    /**
     * 从阻塞队列中获取Netty异步返回结果
     *
     * @param requestUniqueKey
     * @param timeout
     * @return
     */
    public static RemoteResponse getResultValue(String requestUniqueKey, long timeout) {
        RemoteResponseWrapper remoteResponseWrapper = responseMap.get(requestUniqueKey);
        try {
            return remoteResponseWrapper.getResponseQueue().poll(timeout, TimeUnit.MICROSECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            responseMap.remove(requestUniqueKey);
        }
    }
}
